var 
	app 					= require('express')()
  , http					= require('http')
  , server 					= http.createServer(app)
  , structures 				= require('./structures')
  , request					= require('request')
  , winston 				= require('winston')
  , io 						= require('socket.io').listen(server)
  ,	mysql					= require('node-mysql')
  ,	PORT					= -1
  , userMap 				= null
  , logger 					= null
  , mysqlConnection			= null;

serverConfig();
winstonConfig();
socketioConfig();

/****


	Socket.IO events

	
****/

io.sockets.on('connection', function (socket){

	(function(){
		var connected = connect(socket.handshake.query, socket);

		if(connected){
			console.log(socket.handshake.query);
			//sendQuestions();
		}
	})();

	socket.on('insertQuestion', function(data){
		insertQuestion(data);
	});

	socket.on('logout', function(data){
		disconnect(data.ChatId);
	});

	socket.once('disconnect', function(){
		disconnect(socket.id);
	});
});

/****


	Actions


****/

function connect(data, socket){
	try{
		if(data && socket && data.Token && data.DisplayName){
			var token 		= data.Token;
			var displayName = data.DisplayName;

			if(userMap.hasKey(token)){
				disconnect(token);
			}

			var user = new structures.User();

			user.setChatId(token);
			user.setDisplayName(displayName);
			user.setStatus("Conectado");
			user.setSocket(socket);
			user.addRoom('global');

			userMap.set(chatId, user);

			sendGroupConversations(chatId, user);

			return true;
		}
		else{
			disconnect(socket.id);
		}
	}
	catch(error){
		logger.error('Error in %s()', arguments.callee.name, {stack: error.stack});
	}
	
	return false;
}

/**
	- id 		: {string} Either the chat id or the socket id
*/
function disconnect(id){
	try{
		var user = userMap.get(id) || 
				   userMap.get(
				   		userMap.getKeyWithPropertiesAndValue(
				   			['socket', 'id']
				   			, id
				   		)
				   	);

		if(user){
			/*var key = */userMap.removeKey(user.getChatId()/*, leaveAllRooms*/);
			//leaveAllRooms(key);
			if(!user.getSocket().disconnected){
				user.getSocket().disconnect(true);
				updateContactList();
			}
		}
		else if(io.sockets.sockets[id] && !io.sockets.sockets[id].disconnected){
			io.sockets.sockets[id].disconnect(true);
		}
		else{
			logger.info('Unable to disconnect user with unknown id: %s', id);
		}
	}
	catch(error){
		logger.error('Error in %s()', arguments.callee.name, {stack: error.stack});
	}
}

function insertQuestion(data){
	try{
		mysqlConnection.connect();

		var photoPath = "";

		if(data.Photo){
			//Store photo
		}

		var question  = {IdUser: data.IdUser, Description: data.Description, Photo: photoPath, Status: 'Unanswered', CreationDate: 'now()'};

		mysqlConnection.query('INSERT INTO sibt.Question SET ?', question, function(err, result) {
		  	if(err){
		  		throw err;
		  	}
		});
	}
	catch(error){
		logger.error('Error in %s()', arguments.callee.name, {stack: error.stack});
	}
}

function validateSession(data, callback){
	try{
		
		if(!data || !data.query || !data.query.user || !data.query.pass){
			callback(false);
			return;
		}

		mysqlConnection.query('SELECT * FROM sibt.User u WHERE u.UserName = \'' + data.query.user + '\' AND u.Password = \'' + data.query.pass + '\';', function(err, rows, fields) {
		  	if (err) throw err;
			callback(rows && rows.length >= 1);
		});
	}
	catch(error){
		logger.error('Error in %s()', arguments.callee.name, {stack: error.stack});
	}
}


/****


	Util


****/

function getParametizedUrl(params){
	try{
		if(!structures.Dictionary.isDictionary(params)){
			return EXTERNAL_SERVICES_URL;
		}

		return EXTERNAL_SERVICES_URL + '?' + params.toString();
	}
	catch(error){
		logger.error('Error in %s()', arguments.callee.name, {stack: error.stack});
	}
}

function terminateServer(code){
	process.exit(code);
}

function queryLogs(options){
	options = options || {
	    from: new Date - 24 * 60 * 60 * 1000, 		//Yesterday
	    until: new Date,					  		//Today
	    rows: 10,							  		//Last 10 results
	    order: 'desc',								//Print latest logs first
	    fields: ['timestamp', 'message', 'stack']	//Only those fields
  	};

	logger.query(options, function (err, results) {
		console.log(results);
	});
}

/****


	Configuration


****/

function serverConfig(){
	try{
		PORT					= 5002
		userMap 				= new structures.Dictionary();
		mysqlConnection			= mysql.createConnection({
									  host     : 'localhost',
									  user     : 'root',
									  password : '',
								  });
		server.listen(PORT);
	}
	catch(error){
		logger.error('Error in %s()', arguments.callee.name, {stack: error.stack});
		terminateServer(1);
	}
}

function socketioConfig(){
	try{
		io.configure(function() {
		  	io.set('transports', ['websocket','flashsocket', 'xhr-polling', 'jsonp-polling']);
		  	io.set('flash policy port', 843);
		  	io.set('logger', logger);
		  	io.set('match origin protocol', true);
		  	io.set('authorization', function (handshakeData, callback) {
		  		validateSession
				(
					handshakeData
				  , function(validated){
				  		callback(null, validated);
					}
				);
		  	});
		});
	}
	catch(error){
		logger.error('Error in %s()', arguments.callee.name, {stack: error.stack});
		terminateServer(1);
	}
}

function winstonConfig(){
	try{
		winston.loggers.add(
			'application', 
			{
				console: {
			    	colorize: 'true'
				},
			    file: {
			     	filename			: 'chat.log',
		    		handleExceptions	: true,
		    		colorize			: true,
		    		maxsize				: 1024*1024 //1 MB
			    }
			}
		);

		winston.exitOnError = true;

		winston.info('Logging initiated');

		logger = winston.loggers.get('application');
	}
	catch(error){
		console.log('Error in ' + arguments.callee.name + '() ' + error.stack);
		terminateServer(1);
	}
}